package com.ease.plugin {
	import com.ease.core.plugin.ResourceBase;
	import com.ease.plugin.metadata.Metadata;
	import com.ease.plugin.traits.TraitBase;
	import com.ease.plugin.utils.PluginStrings;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;

	import mx.collections.ArrayCollection;
	import mx.core.IContainer;


	/**
     * A MediaElement represents a unified media experience.
     * It may consist of a simple media item, such as a video or a sound.
     * Different instances (or subclasses) can represent different types of media.
     * A MediaElement may also represent a complex media experience composed of
     * multiple items, such as videos, ad banners, SWF overlays, background page branding, etc.
	 *
     * <p>Programmatically, a media element encapsulates a set of media traits and
     * a state space.
	 * The media traits
	 * represent the capabilities of the media element and are dynamic in
	 * nature.  At one moment in time a media element might be
	 * seekable, at another moment it might not be. For example, this could occur
     * if the media element is a video sequence containing unskippable ads.</p>
	 * <p>A media element operates on a media resource.  For example, if the
	 * media element represents a video player, the media resource might
	 * encapsulate a URL to a video stream.
     * If the media element represents a complex media composition,
     * the media resource URL might be a document that references
     * the multiple resources used in the media composition.</p>
     * @see MediaTraitBase
     * @see MediaResourceBase
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 */
	public class BaseElement extends EventDispatcher {
		/**
		 * Constructor.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function BaseElement() {
			super();

			_metadata = createMetadata();
			setupTraitResolvers();
			setupTraits();
		}

		/**
		 * A Vector of MediaTraitType values representing the trait types on this
		 * media element.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function get traitTypes():ArrayCollection {
			// Return a copy of our types vector.
			return _traitTypes;
		}

		/**
		 * Determines whether this media element has a media trait of the
		 * specified type.
		 *
         * @param type The MediaTraitType for the media trait to check for.
		 *
		 * @throws ArgumentError If the parameter is <code>null</code>.
		 * @return <code>true</code> if this media element has a media
		 * trait of the specified class, <code>false</code> otherwise.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function hasTrait(type:String):Boolean {
			if (type == null) {
				throw new ArgumentError(PluginStrings.getString(PluginStrings.INVALID_PARAM));
			}

			return traits[type] != null;
		}

		/**
		 * Returns the media trait of the specified type.
		 *
         * @param type The MediaTraitType for the media trait to return.
		 *
         * @throws ArgumentError If the parameter is <code>null</code>.
         * @return The retrieved trait or <code>null</code> if no such trait exists on this
		 * media element.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function getTrait(type:String):TraitBase {
			if (type == null) {
				throw new ArgumentError(PluginStrings.getString(PluginStrings.INVALID_PARAM));
			}

			return traits[type];
		}

		/**
		 * The media resource that this media element operates on.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function get resource():ResourceBase {
			return _resource;
		}

		public function set resource(value:ResourceBase):void {
			_resource = value;
		}

		/**
		 * The media container that this element uses.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function get container():IContainer
		{
			return _container;
		}

		/**
		 * Adds a Metadata object to this MediaElement under the specified namespace URL.
		 *
		 * @param namespaceURL The namespace URL used to store the Metadata.
		 * @param metadata The Metadata to add.
		 *
		 * @throws ArgumentError if namespaceURL or metadata is null.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function addMetadata(namespaceURL:String, metadata:Metadata):void
		{
//			if (namespaceURL == null || metadata == null)
//			{
//				throw new ArgumentError(OSMFStrings.getString(OSMFStrings.NULL_PARAM));
//			}
//
//			this.metadata.addValue(namespaceURL, metadata);
//
//			dispatchEvent(new MediaElementEvent(MediaElementEvent.METADATA_ADD, false, false, null, namespaceURL, metadata));
//
		}

		/**
		 * Removes the Metadata object that was stored under this MediaElement with
		 * the specified namespace URL.
		 *
		 * @param namespaceURL The namespace URL of the Metadata to remove.
		 *
		 * @returns The removed Metadata, null if no Metadata with the given
		 * namespaceURL exists one this MediaElement.
		 *
		 * @throws ArgumentError If namespaceURL is null.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function removeMetadata(namespaceURL:String):Metadata
		{
			if (namespaceURL == null)
			{
				throw new ArgumentError(PluginStrings.getString(PluginStrings.NULL_PARAM));
			}

			var result:Metadata = metadata.removeValue(namespaceURL) as Metadata;
//			if (result != null)
//			{
//				dispatchEvent(new MediaElementEvent(MediaElementEvent.METADATA_REMOVE, false, false, null, namespaceURL, result));
//			}
			return result;
		}

		/**
		 * Returns the Metadata object that is stored under this MediaElement with
		 * the specified namespace URL.
		 *
		 * @param namespaceURL The namespace URL of the Metadata object to retrieve.
		 *
		 * @returns The Metadata object with the specified namespace URL, null if
		 * no such Metadata object exists on this MediaElement.
		 *
		 * @throws ArgumentError If namespaceURL is null.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		public function getMetadata(namespaceURL:String):Metadata
		{
			if (namespaceURL == null)
			{
			}

			return metadata.getValue(namespaceURL) as Metadata;
		}

		/**
		 * A Vector containing the namespace URLs for all Metadata
		 * objects stored within this MediaElement.
		 **/
		public function get metadataNamespaceURLs():*
		{
			return metadata.keys;
		}

		// Protected
		//

		/**
		 * @private
		 *
		 * Creates the metadata collection class.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		protected function createMetadata():Metadata
		{
			return new Metadata();
		}

		/**
		 * @private
		 **/
		public function get metadata():Metadata
		{
			return _metadata;
		}

		/**
		 * Adds a new media trait to this media element.  If successful,
		 * dispatches a MediaElementEvent.
		 *
         * @param type The MediaTraitType for the media trait to add.
		 * @param trait The media trait to add.
		 *
         * @throws ArgumentError If either parameter is <code>null</code>, or
		 * if the specified type and the type of the media trait don't match,
		 * or if a different instance of the specific trait class has already
		 * been added.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		protected function addTrait(type:String, instance:TraitBase):void
		{
			if (type == null || instance == null || type != instance.traitType)
			{
				throw new ArgumentError(PluginStrings.getString(PluginStrings.INVALID_PARAM));
			}

			setLocalTrait(type, instance);
		}

		/**
		 * Removes a media trait from this media element.  If successful,
		 * dispatches a MediaElementEvent.
		 *
         * @param type The MediaTraitType for the media trait to remove.
		 *
         * @throws ArgumentError If the parameter is <code>null</code>.
         * @return The removed trait or <code>null</code> if no trait was
         * removed.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		protected function removeTrait(type:String):TraitBase
		{
			if (type == null)
			{
				throw new ArgumentError(PluginStrings.getString(PluginStrings.INVALID_PARAM));
			}

			var trait:TraitBase = traits[type];

			return setLocalTrait(type, null);
		}



		/**
		 * @private
		 *
		 * Sets up the trait resolvers for the media elements. Occurs during
		 * construction. Subclasses should override this method and call
		 * addTraitResolver for each trait they wish to add a resolver for.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		protected function setupTraitResolvers():void
		{
		}

		/**
		 * Sets up the traits for this media element.  Occurs during
		 * construction.  Subclasses should override this method and call
		 * addTrait for each trait of their own.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 */
		protected function setupTraits():void
		{
		}

		private function setLocalTrait(type:String, instance:TraitBase):TraitBase
		{
			var result:TraitBase = traits[type];
			if (instance == null)
			{
				// We're processing a trait removal:
				if (result != null)
				{
					// Dispose of any resources:
					result.dispose();

					_traitTypes.removeItemAt(_traitTypes.getItemIndex(type));
					delete traits[type];
				}
			}
			else
			{
				// We're processing a trait addition:
				if (result == null)
				{
					traits[type] = result = instance;
					_traitTypes.addItem(type);

				}
				else if (result != instance)
				{
					throw new ArgumentError(PluginStrings.getString(PluginStrings.TRAIT_INSTANCE_ALREADY_ADDED));
				}
			}

			return result;
		}


		private function onTraitResolverChange(event:Event):void
		{
//			var resolver:MediaTraitResolver = event.target as MediaTraitResolver;
//			processResolvedTraitChange(resolver.type, resolver.resolvedTrait);
		}


		private var traits:Dictionary = new Dictionary();
		private var traitResolvers:Dictionary = new Dictionary();
		private var unresolvedTraits:Dictionary = new Dictionary();

		private var _traitTypes:ArrayCollection = new ArrayCollection();
		private var _resource:ResourceBase;
		private var _metadata:Metadata;

		private var _container:IContainer;
	}
}